package mtvotingserver;

import java.util.*;


/**
 * Tracks and controls server activity at a high level, gives access to 
 * statistics regarding the voting process. Also times the session.
 * Acts as a partial wrapper for the VoteInterpreter.
 * 
 * @author Alex Hrin (0807133)
 */
public class ServerModel {
    
    private long votingStartTime = 0;
    private long votingStopTime = 0;
    private boolean votingStatus = false;
    private VoteInterpreter voteInterpreter = null;
    private int voteInterpreterBufferSize = 8192;

    /**
     * Default constructor
     */
    ServerModel(){
        voteInterpreter = new VoteInterpreter(voteInterpreterBufferSize);
    }
    
    /**
     * Constructor
     * @param size the size of the active client buffer - this will directly 
     *             influence how long it takes for a client to be "forgotten"
     *             by the server if there's no vote confirmation received
     */
    ServerModel(int size) {
        voteInterpreterBufferSize = size;
        voteInterpreter = new VoteInterpreter(voteInterpreterBufferSize);
    }

    /**
     * Determines if the voting session is open of not
     * @return true if a voting session is in progress, false otherwise
     */
    public boolean getVotingStatus() {
        return votingStatus;
    }

    /**
     * Opens or closes a voting session
     * @param votingStatus if set to false will close the current voting session
     *                     and if set to true will begin a new voting session
     *                     Note that opening an already open voting session
     *                     has no effect.
     */
    public void setVotingStatus(boolean votingStatus) {

        if (votingStatus == false && this.votingStatus == true) {
            voteInterpreter.stopVoting();
            votingStopTime = System.nanoTime();
        }
        else if (votingStatus == true && this.votingStatus == false) {
            votingStartTime = System.nanoTime();
            // Remember the options set on the server
            String[] lastOptions = voteInterpreter.getOptions();
            // Create a new interpreter
            voteInterpreter = new VoteInterpreter(voteInterpreterBufferSize);
            // Restore the options
            for (String str : lastOptions)
                voteInterpreter.addOption(str);
            // Start the voting session
            voteInterpreter.start();
        }

        this.votingStatus = votingStatus;
    }

    /**
     * Sums up all the valid votes cast up to this point
     * @return an integer representing the sum of all the valid votes
     */
    public int getTotalVotes() {
        int totalVotes = 0;
        String[] options = voteInterpreter.getOptions();

        for(String str:options)
            totalVotes += voteInterpreter.getVotes(str);

        return totalVotes;
    }

    /**
     * Gets the voting options
     * @return a string array with all registered options
     */
    public String[] getOptions() {
        return voteInterpreter.getOptions();
    }

    /**
     * Gets the number of votes cast for one option
     * @param option the option value
     * @return the number of votes for the option
     */
    public int getVotes(String option) {
        return voteInterpreter.getVotes(option);
    }

    /**
     * Registers an option with the server
     * @param option the value of the options that needs to be registered
     */
    public void addOption(String option) {
        voteInterpreter.addOption(option);
    }
    
    /**
     * Removes a voting option from the server
     * @param option the value of the option
     * @return the number of votes the option got before being removed
     */
    public int removeOption(String option) {
        return voteInterpreter.removeOption(option);
    }

    /**
     * Gets the elapsed time since voting started if the session is still 
     * running or the total time the session ran for if it has stopped
     * @return the time in milliseconds
     */
    public Date getVotingLength() {
        
        Calendar cal = Calendar.getInstance();
        
        if (votingStatus == false) {
            cal.setTimeInMillis((votingStopTime - votingStartTime)/1000000);
            cal.add(Calendar.HOUR, -1);
        }
        else {
            cal.setTimeInMillis((System.nanoTime() - votingStartTime)/1000000);
            cal.add(Calendar.HOUR, -1);
        }
        
        return cal.getTime();
    }

    /**
     * Gets the time at which voting started (in milliseconds)
     * @return the system time at which voting started
     */
    public Date getVotingStartTime() {
        Calendar cal = Calendar.getInstance();

        cal.setTimeInMillis(votingStartTime / 1000000);

        return cal.getTime();
    }

    /**
     * Gets the time at which voting stopped (in milliseconds)
     * @return the system time at which voting stopped
     */
    public Date getVotingStopTime() {
        Calendar cal = Calendar.getInstance();

        cal.setTimeInMillis(votingStopTime / 1000000);
        
        return cal.getTime();
    }
    
    /**
     * Get the voting history of the server since the last poll was made
     * @return
     */
    public ClientModel[] getVotingHistory() {
        
        return voteInterpreter.getClientStats();
    }

    /**
     * Removes all the registered options
     */
    public void clearOptions() {
        voteInterpreter.clearOptions();
    }
    
}